//
//  SEGIbeacon.m
//  ExcellentHome
//
//  Created by 揭婧雯 on 16/10/9.
//  Copyright © 2016年 陈区. All rights reserved.
//

#import "SEGIbeacon.h"
#import <CommonCrypto/CommonDigest.h> // Need to import for CC_MD5 access
@implementation SEGIbeacon

static NSString* const prefix = @"53454749";
static NSString* const value = @"SEGIBEACON2016@%!";
static NSString* const XOR = @"A63CC36A"; //固定异或串

static NSString* const timePrefix = @"53535353";
static NSString* const timeXOR = @"C36AA63C"; //校时固定异或串

//+ (SEGIbeacon*)sharedManager
//{
//    static SEGIbeacon* sharedManager = nil;
//    if (sharedManager) {
//        return sharedManager;
//    }
//    sharedManager = [[SEGIbeacon alloc] init];
//    return sharedManager;
//}

#pragma mark - 生成开门广播数据
/**
 *  生成UUID
 *
 格式： 53454749-TTTT-TTTT-UUUU-CCCCCCCCCCCC
 UUID prefix 固定为SEGI 4字节 0x53454749
 UUUU 用户标识
 TTTT TTTT 日期
 CCCCCCCC 校验码
 *
 *  @return UUID
 */
- (NSString*)UUID
{
    NSString* doubleUUUU = [NSString stringWithFormat:@"%@%@", self.UUUU, self.UUUU];
    NSString* cur = [self pinxCreator:[self getCurrentTime] withPinv:XOR];
    NSString* time = [self pinxCreator:cur withPinv:doubleUUUU];
    _UUID = [[NSString stringWithFormat:@"%@-%@-%@-%@-%@", prefix, [time substringWithRange:NSMakeRange(0, 4)], [time substringWithRange:NSMakeRange(4, 4)], self.UUUU, [self createVerifyCode]] uppercaseString];
    return _UUID;
}

/**
 *  生成major
 *
 格式：当前时间秒数除二
 例如 ，12:31:18秒，转换为数字： 12*3600+31*60+18= 45078
 major=45078/2=22539
 12:31:19秒，转换为数字： 12*3600+31*60+18= 45079
 major=45079/2=22539
 *
 */
- (NSString*)major
{
    //    if (!_major) {
    NSDate* currentDate = [NSDate date]; //获取当前时间，日期
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"hhmmss"];
    NSString* timeStr = [dateFormatter stringFromDate:currentDate];

    int major = ([[timeStr substringWithRange:NSMakeRange(0, 2)] intValue] * 3600 + [[timeStr substringWithRange:NSMakeRange(2, 2)] intValue] * 60 + [[timeStr substringWithRange:NSMakeRange(4, 2)] intValue]) / 2;
    _major = [NSString stringWithFormat:@"%d", major];
    //    }
    return _major;
}

/**
 *  生成minor
 *
 格式：md5(major+deviceid+key+Date+UUUU)的左后2字节。
 UUUU 需要转为十进制字符串 0x3269->12905 参与计算
 *
 */
- (NSString*)minor
{
    //    if (!_minor) {
    self.minorString = [NSString stringWithFormat:@"%@%@%@%@%@", self.major, self.deviceId, value, [self getCurrentTime], [self hexToInt:self.UUUU]];
    NSString* minorMd5 = [self md5:self.minorString];
    NSString* minor = [minorMd5 substringFromIndex:minorMd5.length - 4]; //取最后两个字节
    _minor = [self hexToInt:minor];
    //    }
    return _minor;
}

/**
 *  生成用户标识
 *
 格式：mac(设备UUID)的最后2字节。
 例如ios设备的uuid是19AAB430-9CB8-4325-ACC5-D7D386B68960。
 md5(19AAB430-9CB8-4325-ACC5-D7D386B68960)=85e092372b4d698678ced2bbff163269
 那么用户标识2字节为0x3269.其十进制为12905
 *
 */
- (NSString*)UUUU
{
    if (!_UUUU) {
        self.phoneUUID = [self md5:[[[UIDevice currentDevice] identifierForVendor] UUIDString]];
        _UUUU = [self.phoneUUID substringFromIndex:self.phoneUUID.length - 4]; //取最后两个字节
    }
    return _UUUU;
}

/**
 *  生成校验码
 *
 格式：(MD5(DDDDDDDD+UUUU+TTTTTTTT+KEY))
 例如 设备号是D0000159
 UUUU 0x3269.其十进制为12905
 时间是20160808
 key是SEGIBEACON2016@%!
 校验码计算例子：md5(D00001591290520160808SEGIBEACON2016@%!)=2db61a0bb55d582c50ac09373b81ff5e
 取其中的5-10字节为: b55d582c50ac
 *
 */
- (NSString*)createVerifyCode
{
    NSString* intUUUU = [self hexToInt:self.UUUU]; //用户标识转为十进制
    NSString* codeStr = [NSString stringWithFormat:@"%@%@%@%@", self.deviceId, intUUUU, [self getCurrentTime], value];
    NSString* code = [[self md5:codeStr] substringWithRange:NSMakeRange(8, 12)];
    return code;
}

#pragma mark - 生成时间校验数据
/**
 *  生成timeUUID
 *
 uuid总共16字节：53535353-TTTT-TTTT-RRRR-CCCCCCCCC
 UUID prefix 固定为SSSS     4字节 0x53535353
 TTTTTTTT 当前日期，         4字节，需要变型。
 RRRR 随机码范围从0x0001-0xFFFE	    2字节，注意，不能为0x0000和0xFFFF.
 CCCCCCCC校验码		        6 字节 =(MD5(RRRR+TTTTTTTT+KEY))
 *
 *  @return UUID
 */
- (NSString*)timeUUID
{
    if (!_timeUUID) {
        NSString* doubleRRRR = [NSString stringWithFormat:@"%@%@", self.timeRRRR, self.timeRRRR];
        NSString* cur = [self pinxCreator:[self getCurrentTime] withPinv:timeXOR];
        NSString* time = [self pinxCreator:cur withPinv:doubleRRRR];
        NSString* timeSubString1 = [time substringWithRange:NSMakeRange(0, 4)];
        NSString* timeSubString2 = [time substringWithRange:NSMakeRange(4, 4)];
        _timeUUID = [[NSString stringWithFormat:@"%@-%@-%@-%@-%@", timePrefix, timeSubString1, timeSubString2, self.timeRRRR, [self createTimeVerifyCode]] uppercaseString];
    }
    return _timeUUID;
}

/**
 *  生成timeMinor
 *
 md5(major+key+Date+RRRR)的左后2字节。
 RRRR 转为十进制字符串 0x7C58->31832
 major 为上面生成的 22539
 Date 为 20160808
 Major 为22539
 那minor的计算如下：
 MD5(22539 SEGIBEACON2016@%!2016080812905)=973ecfe9006f3633162710f9bb122a7e
 minor=0x2a7e=10878;
 *
 */
- (NSString*)timeMinor
{
    if (!_timeMinor) {
        self.timeMinorString = [NSString stringWithFormat:@"%@%@%@%@", self.major, value, [self getCurrentTime], [self hexToInt:self.timeRRRR]];
        NSString* minorMd5 = [self md5:self.timeMinorString];
        NSString* minor = [minorMd5 substringFromIndex:minorMd5.length - 4]; //取最后两个字节
        _timeMinor = [self hexToInt:minor];
    }
    return _timeMinor;
}

/**
 *  生成随机码
 *  随机码范围从0x0001-0xFFFE
 */
- (NSString*)timeRRRR
{
    if (!_timeRRRR) { //保证同一次广播中使用的是相同的
        int num = 1 + abs(rand()) % 0xFFFE;
        _timeRRRR = [NSString stringWithFormat:@"%x", num];
    }
    return _timeRRRR;
}

/**
 *  生成校时校验码
 *
 格式：(MD5(RRRR+TTTTTTTT+KEY))
 例如 	 随机码  例如0x7C58 ，参与校验时需转为10进制31832
 时间是20160808
 key是SEGIBEACON2016@%!
 校验码计算例子：	如果随机码是 31832 ，其16进制为	0x7C58	md5(3183220160808SEGIBEACON2016@%!)=48d7416a88a5183cb17fdbfc1b717a50
 取其中的5-10字节为: 88a5183cb17f
 *
 */
- (NSString*)createTimeVerifyCode
{
    NSString* intRRRR = [self hexToInt:self.timeRRRR];
    NSString* codeStr = [NSString stringWithFormat:@"%@%@%@", intRRRR, [self getCurrentTime], value];
    NSString* code = [[self md5:codeStr] substringWithRange:NSMakeRange(8, 12)];
    return code;
}

#pragma mark - 通用方法
/**
 *  十六进制字符串转十进制字符串
 */
- (NSString*)hexToInt:(NSString*)intValue
{
    NSString* str = [NSString stringWithFormat:@"%lu", strtoul([intValue UTF8String], 0, 16)];
    return str;
}
/**
 *  MD5加密
 */
- (NSString*)md5:(NSString*)str
{
    const char* cStr = [str UTF8String];
    unsigned char result[16];
    CC_MD5(cStr, (CC_LONG)strlen(cStr), result); // This is the md5 call
    return [NSString stringWithFormat:
                         @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
                     result[0], result[1], result[2], result[3],
                     result[4], result[5], result[6], result[7],
                     result[8], result[9], result[10], result[11],
                     result[12], result[13], result[14], result[15]];
}

/**
 *  异或算法
 */
- (NSString*)pinxCreator:(NSString*)pan withPinv:(NSString*)pinv
{
    if (pan.length != pinv.length) {
        return nil;
    }
    const char* panchar = [pan UTF8String];
    const char* pinvchar = [pinv UTF8String];

    NSString* temp = [[NSString alloc] init];
    for (int i = 0; i < pan.length; i++) {
        int panValue = [self charToInt:panchar[i]];
        int pinvValue = [self charToInt:pinvchar[i]];

        temp = [temp stringByAppendingString:[NSString stringWithFormat:@"%X", panValue ^ pinvValue]];
    }
    return temp;
}

/**
 *  字符转十进制整型数
 */
- (int)charToInt:(char)tempChar
{
    if (tempChar >= '0' && tempChar <= '9') {
        return tempChar - '0';
    }
    else if (tempChar >= 'A' && tempChar <= 'F') {
        return tempChar - 'A' + 10;
    }
    else if (tempChar >= 'a' && tempChar <= 'f') {
        return tempChar - 'a' + 10;
    }

    return 0;
}

/**
 *  获取当前日期年月日
 */
- (NSString*)getCurrentTime
{
    if (self.networkTime && self.networkTime.length > 0) { //优先使用网络时间
        return self.networkTime;
    }
    else {
        NSDate* currentDate = [NSDate date]; //获取当前时间，日期
        NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"YYYYMMdd"];
        NSString* dateString = [dateFormatter stringFromDate:currentDate];
        return dateString;
    }
}

@end
